home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Frameworks / MacZoop 1.6.5 / Basic Classes / Z Sources / ZApplication.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-18  |  33.1 KB  |  1,307 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            ObjectMacZapp        -- a standard Mac OOP application template
  5. *
  6. *
  7. *
  8. *            ZApplication.cpp    -- the application object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "MacZoop.h"
  23. #include    "ZEventHandler.h"
  24. #include    "ZWindow.h"
  25.  
  26. #ifdef APPEARANCE_MGR_AWARE
  27. #include    "Appearance.h"
  28. #endif
  29.  
  30. #include    "ZPrinter.h"
  31. #include    "ZUndoTask.h"
  32. #include    "CursorUtilities.h"
  33.  
  34.  
  35. // gApplication is the global application object. There is only one, naturally.
  36.  
  37. ZApplication*    gApplication = NULL;
  38. ZMenuBar*        gMenuBar = NULL;
  39.  
  40. // globals
  41.  
  42. OSType        gAppSignature = 'ZAPP';    
  43. Boolean        gIsAColourMac = FALSE;    
  44. tMacInfo    gMacInfo;    
  45.  
  46. // static functions used by the application object
  47.  
  48. static pascal long ZGrowFunc( Size bytesShort );
  49. static GrowZoneUPP    gGZFunc = NewGrowZoneProc( ZGrowFunc );
  50.  
  51. // comment out the following if you do not want printing support
  52.  
  53. #define    PRINTING_ON
  54.  
  55. /*--------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  56.  
  57. ZApplication::ZApplication()
  58.     : ZCommander( NULL )
  59. {
  60.     long    qdFeatures;
  61.     OSErr    theErr;
  62.     
  63.     done = FALSE;
  64.     phase = kInitialising;
  65.     zEH = NULL;
  66.     curUndoTask = NULL;
  67.     itsPrinter = NULL;
  68.     
  69.     appResRefNum = CurResFile();
  70.     
  71.     // set initial filetypes list to a zero handle
  72.     
  73.     FailNIL(itsFileTypes = (OSType**) NewHandle(0));
  74.     
  75.     // create the memory shortage fund
  76.     
  77.     FailNIL( shortageFund = NewHandle( kShortageFundSize ));
  78.     memIsShort = FALSE;
  79.     userHasSeenAlert = FALSE;
  80.     
  81.     // check to see if we are running on a colour Mac
  82.     
  83.     theErr = Gestalt( gestaltQuickdrawFeatures, &qdFeatures );
  84.     gMacInfo.supportsColour = ((theErr == noErr) && (qdFeatures & 1));
  85.     
  86.     // check for the drag manager
  87.     
  88.     theErr = Gestalt( gestaltDragMgrAttr, &qdFeatures );
  89.     gMacInfo.hasDragManager = ((theErr == noErr) && (qdFeatures & 1));
  90.     
  91.     // check for a FPU
  92.     
  93.     theErr = Gestalt( gestaltFPUType, &qdFeatures );
  94.     gMacInfo.hasFPU = ((theErr == noErr) && ((qdFeatures & 1) == 0));
  95.     
  96.     // check for applescript
  97.     
  98.     theErr = Gestalt( gestaltAppleEventsAttr, &qdFeatures );
  99.     gMacInfo.hasAppleEvents = ((theErr == noErr) && (qdFeatures & 1));
  100.     
  101.     // check for QuickTime™
  102.     
  103.     theErr = Gestalt( gestaltQuickTimeVersion, &qdFeatures );
  104.     gMacInfo.hasQuickTime = ((theErr == noErr) && (qdFeatures > 0));
  105.  
  106.     // check for ICM
  107.     
  108.     theErr = Gestalt( gestaltCompressionMgr, &qdFeatures );
  109.     gMacInfo.hasImgCompressionMgr = (theErr == noErr);
  110.  
  111.     // check for appearance manager
  112.     
  113.     #ifdef APPEARANCE_MGR_AWARE
  114.         theErr = Gestalt( gestaltAppearanceAttr, &qdFeatures );
  115.         gMacInfo.hasAppearanceMgr = (( theErr == noErr ) && ( qdFeatures & 1 ));
  116.         
  117.         #if __powerc
  118.         if ( gMacInfo.hasAppearanceMgr )
  119.             gMacInfo.hasAppearanceMgr = ((long)  CreateRootControl != kUnresolvedCFragSymbolAddress );
  120.         #endif
  121.     
  122.     #else
  123.         gMacInfo.hasAppearanceMgr = FALSE;
  124.     
  125.     #endif
  126.     
  127.     // what is the system version?
  128.     
  129.     theErr = Gestalt( gestaltSystemVersion, &qdFeatures );
  130.     gMacInfo.systemVersion = LoWord( qdFeatures );
  131.         
  132.     // initialise the animating cursors, and set the
  133.     // animated watch cursor going.
  134.     
  135.     AppCursorInit();
  136.     gApplication = this;
  137. }
  138.  
  139. /*--------------------------------***  DESTRUCTOR  ***---------------------------------*/
  140.  
  141.  
  142. ZApplication::~ZApplication()
  143. {
  144.     if ( zEH )
  145.         ForgetObject( zEH );
  146.         
  147.     if ( itsPrinter )
  148.         ForgetObject( itsPrinter );
  149.         
  150.     if ( curUndoTask )
  151.         ForgetObject( curUndoTask );
  152.         
  153.     if ( itsFileTypes )
  154.         DisposeHandle((Handle) itsFileTypes);
  155.         
  156.     StopCursorAnimation();
  157. }
  158.  
  159.  
  160. /*--------------------------------***  INITMACZOOP  ***---------------------------------*/
  161. /*    
  162.  
  163. Initialises the application, makes the event handler object and the menubar
  164.  
  165. ----------------------------------------------------------------------------------------*/
  166.  
  167. void        ZApplication::InitMacZoop( const short numMasterBlocks )
  168. {
  169.     if ( phase == kInitialising )
  170.     {
  171.         // init the mac toolbox, memory mangler etc.
  172.         
  173.         InitMacApplication( numMasterBlocks );
  174.         SetGrowZone( gGZFunc );
  175.         SetWatchCursor();
  176.         
  177.         // make the event handler object
  178.         
  179.         MakeEventHandler();
  180.     
  181.         // make the clipboard object
  182.         
  183.         MakeClipboard();
  184.         
  185.         // read any prefs that the user may have set up (default does nothing)
  186.         
  187.         ReadPrefs();
  188.         
  189.         // make printer object and initialise menubar
  190.         
  191.         InitMenuBar();
  192.         MakePrinter();
  193.         
  194.         // call user-function as last part of initialisation- default
  195.         // does nothing but can be overridden to do further set up.
  196.         
  197.         StartUp();
  198.         
  199.         // draw the menubar- note that this is not drawn until StartUp completes,
  200.         // since we allow the programmer the flexibility to use StartUp to create
  201.         // dynamic menus, etc. if they want.
  202.         
  203.         DrawMenuBar();
  204.         phase = kRunning;
  205.         
  206.         // the cursor is not reset here- we let the main event loop do that so that if
  207.         // events are handled immediately, the cursor keeps right on animating until
  208.         // the user gets a chance to do anything.
  209.     }
  210. }
  211.  
  212. /*-----------------------------***  INITMACAPPLICATION  ***-----------------------------*/
  213. /*    
  214.  
  215. Initialises the mac toolbox and memory manager
  216.  
  217. ----------------------------------------------------------------------------------------*/
  218.  
  219.     
  220. void        ZApplication::InitMacApplication( const short numMasterBlocks )
  221. {
  222.     // chant the "Macintosh mantra"...
  223.     
  224.     InitGraf( &qd.thePort );
  225.     InitFonts();
  226.     InitWindows();
  227.     InitMenus();
  228.     TEInit();
  229.     InitDialogs( NULL );
  230.     
  231.     // clear out the event queue in case any stray clicks or keypresses are left there
  232.     
  233.     FlushEvents( everyEvent, 0 );
  234.  
  235.     // see if the program can run on this Mac- if not, we show an alert and exit straight away
  236.     
  237.     if (! CheckCanRun())
  238.     {
  239.         StopCursorAnimation();
  240.         Alert( kCantRunAlertID, NULL );
  241.         ExitToShell();
  242.     }    
  243.     else
  244.     {
  245.         // give yourself enough memory. For a bigger app, you may need to call MoreMasters a few
  246.         // more times. The parameter to this function sets the number of times MoreMasters is
  247.         // called, defaulting to 8, which gives 8 x 64 = 512 handles.
  248.         
  249.         MaxApplZone();
  250.         
  251.         short n = numMasterBlocks;
  252.         
  253.         while( n-- )
  254.             MoreMasters();
  255.     }
  256. }
  257.  
  258. /*--------------------------------***  CHECKCANRUN  ***---------------------------------*/
  259. /*    
  260.  
  261. Examine the machine environment to see if this will run on this Mac. By default, it can
  262. on System 7 or later.
  263.  
  264. ----------------------------------------------------------------------------------------*/
  265.  
  266.  
  267. Boolean        ZApplication::CheckCanRun()
  268. {
  269.     // Returning FALSE will cause the program to
  270.     // immediately show an alert and quit.
  271.     
  272.     // by default, we can run on any Mac with System 7.0 or later.
  273.     
  274.     return( gMacInfo.systemVersion >= 0x0700 );    
  275. }
  276.  
  277.  
  278. /*----------------------------------***  GETNAME  ***-----------------------------------*/
  279. /*    
  280. Get the user-visible name of the application, as seen in the Finder. This works even if
  281. the user has renamed the app, since it finds the filename.
  282. ----------------------------------------------------------------------------------------*/
  283.  
  284.  
  285. void        ZApplication::GetName( Str255 appName )
  286. {
  287.     StringPtr sp = LMGetCurApName();
  288.     CopyPString( sp, appName );
  289. }
  290.  
  291. /*------------------------------------***  RUN  ***-------------------------------------*/
  292. /*    
  293.  
  294. Fetch events and handle them until the user quits
  295.  
  296. ----------------------------------------------------------------------------------------*/
  297.  
  298. void        ZApplication::Run()
  299. {
  300.     // runs the show by asking the event object to get events and handle them. This goes on
  301.     // forever until done is set to TRUE.
  302.     
  303.     if ( phase == kRunning )
  304.     {
  305.         while(! done)
  306.         {
  307.             try
  308.             {
  309.                 // repeatedly get an event, handle an event
  310.                 
  311.                 Process1Event();
  312.                 
  313.                 // deal with the memory shortage situation, if one has arisen as
  314.                 // a result of the last event.
  315.                 
  316.                 CheckLowMemory();
  317.             }
  318.             catch( OSErr theErr )
  319.             {
  320.                 // if here, an exception was thrown. If the error was userCanceledErr,
  321.                 // the alert is not shown, since the exception is legitimate. Thus for
  322.                 // many operations, you need only throw a userCanceledErr exception to
  323.                 // simply invoke the cancel.
  324.                 
  325.                 StopCursorAnimation();
  326.                 HandleError( theErr );
  327.                 
  328.                 // the buck stops here- no exceptions will be thrown beyond this point.
  329.             }
  330.             // stop any animating cursors. This means that a lengthy process need
  331.             // only set the cursor going and can then forget about it. When the
  332.             // app resumes handling events, it will be automatically cancelled.
  333.             
  334.             StopCursorAnimation();
  335.         }
  336.         done = TRUE;
  337.         phase = kQuitting;
  338.     }
  339. }
  340.  
  341.  
  342. /*-----------------------------***  CHECKLOWMEMORY  ***---------------------------------*/
  343. /*    
  344. check if a low memory situation has arisen. If so, inform the user and manage the re-
  345. plenishment of the shortage fund.
  346. ----------------------------------------------------------------------------------------*/
  347.  
  348. void        ZApplication::CheckLowMemory()
  349. {
  350.     if ( memIsShort )
  351.     {
  352.         // some of the shortage fund was used. Try to replenish it:
  353.         
  354.         memIsShort = FALSE;
  355.         
  356.         Handle temp = NewHandle( kShortageFundSize );
  357.         
  358.         // if that resets memIsShort, then the grow zone func was called, so we
  359.         // are not in the clear yet. However, if the grow zone func wasn't
  360.         // called, then we can safely get rid of that handle and replace it with
  361.         // this one
  362.         
  363.         if ( memIsShort )
  364.         {
  365.             if ( temp )
  366.                 DisposeHandle( temp );
  367.             
  368.             // couldn't replenish the fund, so if the user hasn't seen the
  369.             // warning yet, show it now.
  370.             
  371.             if (! userHasSeenAlert)
  372.             {
  373.                 StopCursorAnimation();
  374.                 Alert( kMemoryLowAlertID, NULL );
  375.                 userHasSeenAlert = TRUE;
  376.             }
  377.             
  378.             // if memIsShort is tRUE, it affects UpdateMenus such that New and Open are
  379.             // greyed out. This is an attempt to stop the user creating things that will
  380.             // eat up even more memory. You might want to use the same technique for commands
  381.             // of your own that may allocate lots of memory. For this reason, memIsShort is
  382.             // a public member.
  383.         }
  384.         else
  385.         {
  386.             // fund replenished, so get rid of any remaining fund and replace it
  387.             // with the newly allocated shortage fund.
  388.             
  389.             DisposeHandle( shortageFund );
  390.             shortageFund = temp;
  391.             userHasSeenAlert = FALSE;
  392.         }
  393.     }
  394. }
  395.  
  396.  
  397. /*-------------------------------***  HANDLEERROR  ***----------------------------------*/
  398. /*    
  399. display an alert indicating the error (some errors do nothing, likewise noErr is ignored)
  400. ----------------------------------------------------------------------------------------*/
  401.  
  402. void        ZApplication::HandleError( OSErr theErr )
  403. {
  404.     // handles the error passed by displaying an alert. This is called by the exception
  405.     // handler for the application, but you can call it at any time. Some errors are "silent"
  406.     // in that the exception does not result in a message. These include userCanceled, kSilent
  407.     // Err, and aeEventNotHandled. Override this if you want to handle errors differently.
  408.     
  409.     if ( theErr != userCanceledErr &&
  410.          theErr != kSilentErr       &&
  411.          theErr != noErr            &&
  412.          theErr != errAEEventNotHandled )
  413.     {
  414.         StringHandle    errExpH;    
  415.         Str255            errMsgStr;
  416.         Str31            errExplStr;
  417.         Str15            errIDStr;
  418.         
  419.         NumToString( theErr, errIDStr );
  420.         
  421.         // try to build a meaningful error message by looking for an 'Estr'
  422.         // resource with the same iD as the error. If found, this is concatenated
  423.         // onto the generic error stub and displayed. If not found, the default
  424.         // explanation "an error occurred" is used.
  425.         
  426.         GetIndString( errMsgStr, 128, 10 );
  427.         
  428.         errExpH = (StringHandle) GetResource( 'Estr', theErr );
  429.         
  430.         if ( errExpH )
  431.         {
  432.             ConcatPStrings( errMsgStr, *errExpH );     
  433.             ReleaseResource((Handle) errExpH );
  434.         }
  435.         else
  436.         {
  437.             GetIndString( errExplStr, 128, 11 );
  438.             ConcatPStrings( errMsgStr, errExplStr );
  439.         }
  440.         
  441.         ParamText( errIDStr, errMsgStr, NULL, NULL );
  442.         Alert( kExceptionAlertID, NULL );
  443.     }
  444. }
  445.  
  446.  
  447. /*------------------------------***  PROCESS1EVENT  ***---------------------------------*/
  448. /*    
  449. get an event, dispatch an event, get an event, dispatch...
  450. ----------------------------------------------------------------------------------------*/
  451.  
  452. void        ZApplication::Process1Event()
  453. {
  454.     zEH->GetAnEvent();
  455.     zEH->DispatchAnEvent();
  456. }
  457.  
  458.  
  459.  
  460. /*-----------------------------***  GETCURRENTEVENT  ***--------------------------------*/
  461. /*
  462. return the current event in progress, with FALSE if it was a null event, else TRUE.    
  463. ----------------------------------------------------------------------------------------*/
  464.  
  465. Boolean        ZApplication::GetCurrentEvent( EventRecord* anEvent )
  466. {
  467.     zEH->GetLatestEvent( anEvent );
  468.     
  469.     return( anEvent->what != nullEvent );
  470. }
  471.  
  472.  
  473. /*--------------------------------***  GETCLICKS  ***-----------------------------------*/
  474. /*    
  475. return the number of clicks counted by the event handler in the same place. Returns 1 for
  476. single click, 2 for double, 3 for triple, etc.
  477. ----------------------------------------------------------------------------------------*/
  478.  
  479. short        ZApplication::GetClicks()
  480. {
  481.     return zEH->GetClicks();
  482. }
  483.  
  484.  
  485. /*-------------------------------***  INBACKGROUND  ***---------------------------------*/
  486. /*    
  487. return TRUE if the application is in the background, FALSE in foreground.
  488. ----------------------------------------------------------------------------------------*/
  489.  
  490. Boolean        ZApplication::InBackground()
  491. {
  492.     return zEH->InBackground();
  493. }
  494.  
  495.  
  496. /*-----------------------------------***  QUIT  ***-------------------------------------*/
  497. /*    
  498.  
  499. close all of the windows. If successful, delete the application and return TRUE
  500.  
  501. ----------------------------------------------------------------------------------------*/
  502.  
  503. Boolean        ZApplication::Quit()
  504. {
  505.     if ( phase == kQuitting )
  506.     {
  507.         CloseAll();
  508.         
  509.         // the Quit can be abandoned by resetting <done> to FALSE. If this
  510.         // has not occurred, then truly say goodbye.
  511.         
  512.         if ( done )
  513.         {
  514.             ShutDown();
  515.             ForgetThis();
  516.         }
  517.     }
  518.     return done;
  519. }
  520.  
  521.  
  522. /*-------------------------------***  REQUESTQUIT  ***----------------------------------*/
  523. /*    
  524.  
  525. ask the application to quit. This is called by choosing Quit from the File menu, for example.
  526.  
  527. ----------------------------------------------------------------------------------------*/
  528.  
  529.  
  530. void        ZApplication::RequestQuit()
  531. {
  532.     done = TRUE;
  533. }
  534.  
  535. /*----------------------------***  HANDLEAPPLEEVENT  ***--------------------------------*/
  536. /*    
  537. Handle the four required apple events. If you override this to handle your own apple
  538. events, be sure to call the inherited method for everything else.
  539. ----------------------------------------------------------------------------------------*/
  540.  
  541. void        ZApplication::HandleAppleEvent(    AEEventClass aeClass, AEEventID aeID,
  542.                                             AppleEvent* aeEvt, AppleEvent* reply )
  543. {
  544.     if ( aeClass == kCoreEventClass )
  545.     {
  546.         FSSpec        aFile;
  547.         AEDescList    docList;
  548.         long        i, n;
  549.         AEKeyword    keyWrd;
  550.         DescType    retType;
  551.         Size        actualSize;
  552.         FInfo        fi;
  553.         
  554.         switch ( aeID )
  555.         {
  556.             case kAEOpenApplication:
  557.                 #ifndef NO_UNTITLED_STARTUP_WINDOW
  558.                 OpenNewWindow();
  559.                 #endif
  560.                 break;
  561.             
  562.             case kAEOpenDocuments:
  563.                 FailOSErr( AEGetParamDesc( aeEvt, keyDirectObject, typeAEList, &docList ));    
  564.                 FailOSErr( AECountItems( &docList, &n ));
  565.                 
  566.                 // get each document and open it
  567.                 try
  568.                 {
  569.                     for (i = 1; i <= n; i++)
  570.                     {
  571.                         FailOSErr( AEGetNthPtr( &docList,
  572.                                                 i, 
  573.                                                 typeFSS, 
  574.                                                 &keyWrd,
  575.                                                 &retType, 
  576.                                                 &aFile, 
  577.                                                 sizeof( FSSpec ), 
  578.                                                 &actualSize ));
  579.                         
  580.                         FailOSErr( FSpGetFInfo( &aFile, &fi ));
  581.                         
  582.                         // open the file into a window and select it
  583.                         
  584.                         OpenFile( aFile, fi.fdType );
  585.                     }
  586.                 }
  587.                 catch( OSErr err )
  588.                 {
  589.                     AEDisposeDesc( &docList );
  590.                     
  591.                     throw err;
  592.                 }
  593.                 FailOSErr( AEDisposeDesc( &docList ));
  594.                 break;
  595.             
  596.             case kAEPrintDocuments:
  597.                 FailOSErr( AEGetParamDesc( aeEvt, keyDirectObject, typeAEList, &docList ));    
  598.                 FailOSErr( AECountItems( &docList, &n ));
  599.                 
  600.                 // ask the application to show the page setup dialog
  601.                 
  602.                 DoPageSetup();
  603.                 
  604.                 // get each document passed by the finder
  605.                 
  606.                 try
  607.                 {
  608.                     for (i = 1; i <= n; i++)
  609.                     {
  610.                         FailOSErr( AEGetNthPtr( &docList,
  611.                                                 i, 
  612.                                                 typeFSS, 
  613.                                                 &keyWrd,
  614.                                                 &retType, 
  615.                                                 &aFile, 
  616.                                                 sizeof( FSSpec ), 
  617.                                                 &actualSize ));
  618.                         
  619.                         FailOSErr(FSpGetFInfo( &aFile, &fi ));
  620.                         
  621.                         // open the file into a window and select it
  622.                         
  623.                         OpenFile( aFile, fi.fdType );
  624.                         
  625.                         // update the window (not strictly needed, but looks better)
  626.                         
  627.                         zEH->HandleWindowUpdate( mostRecent->GetMacWindow());
  628.                         
  629.                         // ask the application to print the document
  630.                         
  631.                         DoPrint();
  632.                         
  633.                         // that done, we can close the window and move on to the next
  634.                         
  635.                         mostRecent->Close( GetPhase());
  636.                     }
  637.                 }
  638.                 catch( OSErr err )
  639.                 {
  640.                     AEDisposeDesc( &docList );
  641.                     
  642.                     throw err;
  643.                 }
  644.                 
  645.                 FailOSErr( AEDisposeDesc( &docList ));
  646.                 break;
  647.             
  648.             case kAEQuitApplication:
  649.                 RequestQuit();
  650.                 break;
  651.             
  652.             default:
  653.                 inherited::HandleAppleEvent( aeClass, aeID, aeEvt, reply );
  654.                 break;    
  655.         }
  656.     }
  657.     else
  658.         inherited::HandleAppleEvent( aeClass, aeID, aeEvt, reply );
  659. }
  660.  
  661.  
  662. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  663. /*    
  664.  
  665. Handle commands (menu items) that apply to the application as a whole, like Quit.
  666.  
  667. ----------------------------------------------------------------------------------------*/
  668.  
  669. void        ZApplication::HandleCommand( const long aCmd )
  670. {
  671.     // handle commands at the application level. This includes quit, new, open, etc.
  672.     
  673.     FSSpec        aFile;
  674.     OSType        anFType;
  675.     
  676.     switch( aCmd )
  677.     {
  678.         case kCmdAbout:
  679.             AboutBox();
  680.             break;
  681.         case kCmdNew:
  682.             OpenNewWindow();                        // open a new "untitled" window
  683.             break;
  684.         case kCmdOpen:
  685.             if (PickFile( &aFile, &anFType ))        // choose a file
  686.                 OpenFile( aFile, anFType );            // open the file into a window
  687.             break;
  688.         case kCmdQuit:
  689.             RequestQuit();                            // the app should now quit
  690.             break;
  691.         case kCmdPageSetup:
  692.             DoPageSetup();
  693.             break;
  694.         case kCmdPrint:
  695.             DoPrint();
  696.             break;
  697.         case kCmdUndo:
  698.             if ( curUndoTask )    // undo item available?
  699.             {
  700.                 SetWatchCursor();
  701.                 if (curUndoTask->IsUndone())        // undo or redo?
  702.                     curUndoTask->Redo();            // redo the task
  703.                 else
  704.                     curUndoTask->Undo();            // undo the task
  705.             }
  706.             break;
  707.     }
  708. }
  709.  
  710.  
  711. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  712.  
  713. void        ZApplication::HandleCommand( const short menuID, const short itemID )
  714. {
  715.     GrafPtr        savePort;
  716.     Str255        daName;
  717.     
  718.     if ( menuID == kAppleMenuID &&
  719.          itemID > 2 )
  720.     {
  721.         // open desk accessories.
  722.         GetMenuItemText( GetMenuHandle( menuID ), itemID, daName );
  723.         GetPort( &savePort );
  724.         OpenDeskAcc( daName );
  725.         SetPort( savePort );
  726.     }
  727. }
  728.  
  729.  
  730. /*-------------------------------***  UPDATEMENUS  ***----------------------------------*/
  731. /*    
  732.  
  733. enable the menu commands that the app can handle at the moment.
  734.  
  735. ----------------------------------------------------------------------------------------*/
  736.  
  737. void    ZApplication::UpdateMenus()
  738. {
  739.     // enable the menu commands that pertain to the application. This includes "New",
  740.     // "Quit" and "About" amongst others
  741.     
  742.     // apple menu
  743.     
  744.     gMenuBar->EnableCommand( kCmdAbout );
  745.         
  746.     // file menu
  747.     
  748.     // if memory is currently short, do not enable new or open, since those are the
  749.     // commands that are likely to allocate a lot more memory, which we do not have.
  750.     
  751.     if (! memIsShort)
  752.     {
  753.         gMenuBar->EnableCommand( kCmdNew );
  754.         gMenuBar->EnableCommand( kCmdOpen );
  755.     }
  756.     gMenuBar->EnableCommand( kCmdQuit );
  757.         
  758.     // enable the printing items if there is a printer and the front window
  759.     // supports printing.
  760.     
  761.     if ( itsPrinter )
  762.     {
  763.         gMenuBar->EnableCommand( kCmdPageSetup );
  764.     
  765.         ZWindow*    fWindow = GetFrontWindow();
  766.         
  767.         if (fWindow && fWindow->IsPrintable())
  768.             gMenuBar->EnableCommand( kCmdPrint );
  769.     }    
  770.     
  771.     // edit:
  772.     
  773.     UpdateUndo();
  774. }
  775.  
  776.  
  777. /*-------------------------------***  DOPAGESETUP  ***----------------------------------*/
  778. /*
  779. handle the Page Setup command    
  780. ----------------------------------------------------------------------------------------*/
  781.  
  782. void    ZApplication::DoPageSetup()
  783. {
  784.     if ( itsPrinter )
  785.     {
  786.         gWindowManager->Deactivate();
  787.         itsPrinter->PageSetUp();
  788.         gWindowManager->Activate();
  789.     }
  790. }
  791.  
  792. /*----------------------------------***  DOPRINT  ***-----------------------------------*/
  793. /*
  794. handle the Print command    
  795. ----------------------------------------------------------------------------------------*/
  796.  
  797. void    ZApplication::DoPrint()
  798. {
  799.     if ( itsPrinter )
  800.     {
  801.         ZWindow*    aWindow = GetFrontWindow();
  802.         
  803.         gWindowManager->Deactivate();
  804.         itsPrinter->Print( aWindow );
  805.         gWindowManager->Activate();
  806.     }
  807. }
  808.  
  809.  
  810. /*---------------------------------***  ABOUTBOX  ***-----------------------------------*/
  811. /*    
  812. display the application's about box
  813. ----------------------------------------------------------------------------------------*/
  814.  
  815. void    ZApplication::AboutBox()
  816. {
  817.     gWindowManager->Deactivate();
  818.     (void) Alert( kAboutBoxID, NULL );
  819.     gWindowManager->Activate();
  820. }
  821.  
  822.  
  823. /*----------------------------------***  SETTASK  ***-----------------------------------*/
  824. /*    
  825. update the current global undo task
  826. ----------------------------------------------------------------------------------------*/
  827.  
  828. void    ZApplication::SetTask( ZUndoTask* aTask )
  829. {
  830.     if ( curUndoTask )
  831.         ForgetObject( curUndoTask );
  832.         
  833.     curUndoTask = aTask;
  834. }
  835.  
  836. /*--------------------------------***  UPDATEUNDO  ***----------------------------------*/
  837. /*    
  838. update the Undo menu item to reflect the current undo task
  839. ----------------------------------------------------------------------------------------*/
  840.  
  841. void    ZApplication::UpdateUndo()
  842. {
  843.     Str255        undoMenuStr;
  844.     
  845.     if ( curUndoTask )
  846.     {
  847.         // a task available, so update the undo menu item to the task string.
  848.         
  849.         Str63        taskStr;
  850.         
  851.         if (curUndoTask->IsUndone())
  852.             GetIndString( undoMenuStr, kMiscStrListID, kRedoStrIndex );
  853.         else
  854.             GetIndString( undoMenuStr, kMiscStrListID, kUndoStrIndex );
  855.             
  856.         // add the task name
  857.         
  858.         curUndoTask->GetTaskString( taskStr );
  859.         ConcatPStrings( undoMenuStr, taskStr );
  860.         
  861.         // set the menu item to the task name
  862.         
  863.         gMenuBar->SetCommandText( kCmdUndo, undoMenuStr );
  864.         
  865.         // there is a task, but does it refer to the front window? If not,
  866.         // then do not actually enable the command.
  867.  
  868.         if ((curUndoTask->GetUndoTarget() == GetFrontWindow()) &&
  869.             (curUndoTask->GetUndoTarget() != NULL))
  870.             gMenuBar->EnableCommand( kCmdUndo );
  871.     }
  872.     else
  873.     {
  874.         // if no task, just show a dimmed "Can't Undo"
  875.         
  876.         gMenuBar->SetCommandText( kCmdUndo, kMiscStrListID, kCantUndoStrIndex );
  877.     }
  878. }
  879.  
  880.  
  881. /*-------------------------------***  INITMENUBAR  ***----------------------------------*/
  882. /*    
  883. set up the menubar object for managing the main menus
  884. ----------------------------------------------------------------------------------------*/
  885.  
  886. void        ZApplication::InitMenuBar()
  887. {
  888.     // installs the menu bar. By default, we just install 'MBAR' ID = 128, which means you
  889.     // don't need to override this to get other menus- just create the resources you want.
  890.     
  891.     FailNIL( gMenuBar = new ZMenuBar( kStdMenubarID ));
  892.  
  893.     gMenuBar->InitMenuBar();
  894. }
  895.  
  896. /*--------------------------------***  MAKECLIPBOARD  ***-------------------------------*/
  897. /*    
  898.  
  899. Make the clipboard object. By default, this is a ZClipboard.
  900. ----------------------------------------------------------------------------------------*/
  901.  
  902. void        ZApplication::MakeClipboard()
  903. {
  904.     FailNIL( gClipboard = new ZClipboard());
  905. }
  906.  
  907.  
  908. /*------------------------------***  MAKEEVENTHANDLER  ***------------------------------*/
  909. /*    
  910.  
  911. Make the event handler object. By default, this is a ZEventHandler. This also makes the
  912. window manager, since that is functionally related to the event handler.
  913. ----------------------------------------------------------------------------------------*/
  914.  
  915.  
  916. void        ZApplication::MakeEventHandler()
  917. {
  918.     // make the event handler
  919.     
  920.     FailNIL( zEH = new ZEventHandler());
  921.     
  922.     // make the window manager for handling floating windows, etc.
  923.     
  924.     FailNIL( gWindowManager = new ZWindowManager());
  925.     
  926.     // install handlers for the four required events
  927.     
  928.     zEH->InstallApplescriptHandlers();        
  929. }
  930.  
  931.  
  932. /*--------------------------------***  MAKEPRINTER  ***---------------------------------*/
  933. /*    
  934.  
  935. creates a new printer object for handling the print commands
  936.  
  937. ----------------------------------------------------------------------------------------*/
  938.  
  939. void        ZApplication::MakePrinter()
  940. {
  941.     #ifdef PRINTING_ON
  942.     
  943.     FailNIL( itsPrinter = new ZPrinter());
  944.     
  945.     #endif
  946. }
  947.  
  948. /*------------------------------***  MAKENEWWINDOW  ***---------------------------------*/
  949. /*    
  950.  
  951. creates a new window object and initialises it. It does not show it yet. Normally you will
  952. override this method to create your own useful kinds of windows. However, even if you don't
  953. you'll still get a window that works. Eat your heart out Sprocket!
  954. ----------------------------------------------------------------------------------------*/
  955.  
  956. void        ZApplication::MakeNewWindow()
  957. {
  958.     FailNIL( mostRecent = new ZWindow( this,  kUntitledWindowID ));
  959.     
  960.     try
  961.     {
  962.         mostRecent->InitZWindow();
  963.     }
  964.     catch( OSErr err )
  965.     {
  966.         ForgetObject( mostRecent );
  967.         
  968.         throw err;
  969.     }
  970. }
  971.  
  972.  
  973. /*------------------------------***  OPENNEWWINDOW  ***---------------------------------*/
  974. /*    
  975.  
  976. creates a new window object and initialises it. It then shows it and makes it active.
  977.  
  978. ----------------------------------------------------------------------------------------*/
  979.  
  980. void        ZApplication::OpenNewWindow()
  981. {
  982.     mostRecent = NULL;
  983.     
  984.     MakeNewWindow();
  985.     
  986.     if ( mostRecent )
  987.     {
  988.         gWindowManager->InitiallyPlace( mostRecent );
  989.         mostRecent->Select();
  990.     }
  991. }
  992.  
  993.  
  994. /*---------------------------------***  CLOSEALL  ***-----------------------------------*/
  995. /*    
  996.  
  997. closes all of the application's windows. If one refuses to close, this will abort a Quit.
  998.  
  999. ----------------------------------------------------------------------------------------*/
  1000.  
  1001. void        ZApplication::CloseAll( Boolean closeFloaters )
  1002. {
  1003.     // closes all of the windows. Called as part of the quit operation. This also checks
  1004.     // for the disableAutoClose flag so that windows don't get closed that deliberately
  1005.     // set the flag. The techniques used in this method are necessary so that all windows
  1006.     // are iterated over correctly even when some get closed.
  1007.  
  1008.     ZWindow*    zappWindow;
  1009.     WindowPeek    w;
  1010.     
  1011.     w = (WindowPeek) FrontWindow();
  1012.     
  1013.     while( w )
  1014.     {
  1015.         zappWindow = GetZWindow((WindowPtr) w );
  1016.         w = w->nextWindow;
  1017.         
  1018.         if ( zappWindow &&
  1019.             !zappWindow->NoAutoClose() &&
  1020.             ( closeFloaters == zappWindow->Floats()) &&
  1021.             ! zappWindow->Close( phase ))
  1022.         {
  1023.             phase = kRunning;
  1024.             done = FALSE;
  1025.             
  1026.             break;
  1027.         }            
  1028.     }
  1029.     
  1030.     // if we're quitting and the user hasn't cancelled, close all the "uncloseables"
  1031.     // so that things are cleaned up properly. Uncloseables can still cancel the
  1032.     // quit, though this would be a very strange use of such a window!
  1033.     
  1034.     if ( phase == kQuitting )
  1035.     {
  1036.         w = (WindowPeek) FrontWindow();
  1037.         
  1038.         while( w )
  1039.         {
  1040.             zappWindow = GetZWindow((WindowPtr) w );
  1041.             w = w->nextWindow;
  1042.             
  1043.             if (  zappWindow &&
  1044.                  !zappWindow->Close( phase ))
  1045.             {
  1046.                 phase = kRunning;
  1047.                 done = FALSE;
  1048.                 
  1049.                 break;
  1050.             }            
  1051.         }
  1052.     }
  1053. }
  1054.  
  1055.  
  1056. /*------------------------------***  GETFRONTWINDOW  ***--------------------------------*/
  1057. /*    
  1058.  
  1059. returns the active window object, if there is one
  1060.  
  1061. ----------------------------------------------------------------------------------------*/
  1062.  
  1063. ZWindow*    ZApplication::GetFrontWindow()
  1064. {
  1065.     return ( gWindowManager->GetTopWindow());
  1066. }
  1067.  
  1068.  
  1069. /*----------------------------------***  PICKFILE  ***----------------------------------*/
  1070. /*    
  1071.  
  1072. displays the standard file dialog for selecting a file, and returns its filespec.
  1073.  
  1074. ----------------------------------------------------------------------------------------*/
  1075.  
  1076.  
  1077. Boolean        ZApplication::PickFile( FSSpec* aFile, OSType* fType )
  1078. {
  1079.     // uses standard file to choose a file to open to a window. By default, no files types
  1080.     // are added to the list, which we here interpret to mean "show all files".
  1081.     
  1082.     StandardFileReply    aReply;
  1083.     short                numTypes;
  1084.     
  1085.     HLock((Handle) itsFileTypes );
  1086.     numTypes = GetHandleSize((Handle) itsFileTypes ) / sizeof( OSType );
  1087.     
  1088.     // if no types in the list, show all of them
  1089.     
  1090.     if( numTypes <= 0 )
  1091.         numTypes = -1;
  1092.     
  1093.     StopCursorAnimation();
  1094.     gWindowManager->Deactivate();
  1095.     
  1096.     // display the dialog
  1097.     StandardGetFile( NULL, numTypes, *itsFileTypes, &aReply );
  1098.     HUnlock((Handle) itsFileTypes );
  1099.     
  1100.     gWindowManager->Activate();
  1101.     
  1102.     if ( aReply.sfGood )
  1103.     {
  1104.         *aFile = aReply.sfFile;
  1105.         *fType = aReply.sfType;
  1106.         return TRUE;
  1107.     }
  1108.     else
  1109.         return FALSE;
  1110.  
  1111. }
  1112.  
  1113.  
  1114. /*----------------------------------***  OPENFILE  ***----------------------------------*/
  1115. /*    
  1116.  
  1117. creates a new window and asks it to open the file. It then shows the window and activates it.
  1118.  
  1119. ----------------------------------------------------------------------------------------*/
  1120.  
  1121. void        ZApplication::OpenFile( const FSSpec& aFile, const OSType fType )
  1122. {
  1123.     // opens the file into a new window. This is equivalent to OpenNewWindow, but
  1124.     // for when the user chose a file with the Open command
  1125.     
  1126.     mostRecent = NULL;
  1127.     
  1128.     SetWatchCursor();
  1129.     MakeNewWindow();
  1130.     
  1131.     // window created, so ask it to open the chosen file
  1132.     
  1133.     if ( mostRecent )
  1134.     {
  1135.         try
  1136.         {
  1137.             mostRecent->SetFile( aFile );
  1138.             mostRecent->OpenFile( fType );
  1139.             gWindowManager->InitiallyPlace( mostRecent );
  1140.             mostRecent->Select();
  1141.         }
  1142.         catch( OSErr err )
  1143.         {
  1144.             ForgetObject( mostRecent );
  1145.             throw err;
  1146.         }
  1147.     }
  1148. }
  1149.  
  1150.  
  1151. /*--------------------------------***  ADDFILETYPE  ***---------------------------------*/
  1152. /*    
  1153. adds <aType> to the list of types this application will show in the Open dialog. You can
  1154. call this for each type your application can open. This ignores duplicates.
  1155. -----------------------------------------------------------------------------------------*/
  1156.  
  1157. void        ZApplication::AddFileType( const OSType aType )
  1158. {
  1159.     // adds the file type to the list of types, if not already there
  1160.     
  1161.     short    nTypes, i;
  1162.     
  1163.     nTypes = GetHandleSize((Handle) itsFileTypes ) / sizeof( OSType );
  1164.     
  1165.     // check that the file type we are adding is unique in the list
  1166.     
  1167.     for ( i = 0; i < nTypes; i++ )
  1168.     {
  1169.         if ( (*itsFileTypes)[i] == aType )
  1170.             return;
  1171.     }
  1172.     
  1173.     // if we are still here, type is unique, so append it
  1174.     // first grow the handle
  1175.     
  1176.     SetHandleSize((Handle) itsFileTypes, sizeof(OSType) * (nTypes + 1) );
  1177.     FailOSErr( MemError() );
  1178.     
  1179.     // set the new entry
  1180.     
  1181.     (*itsFileTypes)[nTypes] = aType;
  1182. }
  1183.  
  1184.  
  1185.  
  1186. /*------------------------------***  MEMORYSHORTAGE  ***--------------------------------*/
  1187. /*    
  1188.  
  1189. called from the growzone proc when memory needs to be freed. This releases some or all
  1190. of the shortage fund, but you can override it to make additional sacrifices if need be.
  1191.  
  1192. ----------------------------------------------------------------------------------------*/
  1193.  
  1194. Boolean        ZApplication::MemoryShortage( const Size bytesShort )
  1195. {
  1196.     // this is called when the memory manager gets into dire straits. We can free some or all
  1197.     // of our emergency fund to satisfy the request. If we succeed, we return TRUE, else FALSE.
  1198.     
  1199.     Size    fundSize = 0;
  1200.     Handle    gzHandle;
  1201.     
  1202.     // get the handle the mem manager is dealing with at the moment. This is important since
  1203.     // this might be the shortage fund itself. If it is, we can't resize it, so we really
  1204.     // are in deep do-do. In this case, we flag memIsShort and hope the user will not ignore
  1205.     // the message!
  1206.     
  1207.     gzHandle = GZSaveHnd();
  1208.     
  1209.     if ( gzHandle != shortageFund )
  1210.     {
  1211.         fundSize = GetHandleSize( shortageFund );
  1212.         
  1213.         // release all or some of the memory to try and satisfy the request
  1214.         
  1215.         if ( fundSize <= bytesShort )
  1216.             SetHandleSize( shortageFund, 0 );
  1217.         else
  1218.             SetHandleSize( shortageFund, fundSize - bytesShort );
  1219.     }
  1220.     // flag the shortage so we can inform the user
  1221.     
  1222.     memIsShort = TRUE;
  1223.     
  1224.     // did we actually manage to free the requested amount?
  1225.     
  1226.     return( fundSize > bytesShort );
  1227. }
  1228.  
  1229.  
  1230. #pragma mark -
  1231. /*---------------------------------***  ZGROWFUNC  ***----------------------------------*/
  1232. /*    
  1233.  
  1234. memory manager callback proc.
  1235. ----------------------------------------------------------------------------------------*/
  1236.  
  1237. static pascal long ZGrowFunc( Size bytesShort )
  1238. {
  1239.     Boolean bytesFreed;
  1240.     Size    growBytes;
  1241.     
  1242.     // call application object to free some memory
  1243.     
  1244.     bytesFreed = gApplication->MemoryShortage( bytesShort );
  1245.     
  1246.     // try to compact and purge the memory after the
  1247.     // application has done something to free some up.
  1248.     
  1249.     (void) MaxMem( &growBytes );
  1250.     
  1251.     return bytesFreed;
  1252. }
  1253.  
  1254.  
  1255. /******************************************************************************
  1256.  CopyPString
  1257.  
  1258.         Copy a Pascal string
  1259.  ******************************************************************************/
  1260.  
  1261. void    CopyPString( ConstStr255Param srcString, Str255 destString )
  1262. {
  1263.     BlockMoveData( srcString, destString, MIN( srcString[0] + 1, 255 ));
  1264. }
  1265.  
  1266.  
  1267. /******************************************************************************
  1268.  ConcatPStrings
  1269.  
  1270.         Concatenate two Pascal strings by attaching the second string on
  1271.         the end of the first string.
  1272.  ******************************************************************************/
  1273.  
  1274. void    ConcatPStrings( Str255 first, ConstStr255Param second )
  1275. {
  1276.  
  1277.     short charsToCopy;
  1278.  
  1279.     // Truncate if concatenated string would be longer than 255 chars.
  1280.  
  1281.     charsToCopy = MIN(second[0], 255 - first[0]);
  1282.     BlockMoveData(second + 1, first + first[0] + 1, (long) charsToCopy);
  1283.     first[0] += charsToCopy;
  1284. }
  1285.  
  1286.  
  1287. /*------------------------------***  RUNAPPLICATION  ***--------------------------------*/
  1288. /*    
  1289. standard function to run the application. Your main() function must make the relevant
  1290. ZApplication object, assign it to gApplication, then call this.
  1291. ----------------------------------------------------------------------------------------*/
  1292.  
  1293. void    RunApplication()
  1294. {
  1295.     if (gApplication)
  1296.     {    
  1297.         gApplication->InitMacZoop();            // initialise the whole kaboodle. This is
  1298.                                                 // NOT done by the constructor since you might
  1299.                                                 // want to override the initialisation.
  1300.         do
  1301.         {
  1302.             gApplication->Run();                // run the application until the user quits
  1303.         }
  1304.         while (! gApplication->Quit());            // try to quit
  1305.     }
  1306. }
  1307.